<?php


namespace app\admin\service;


use app\common\model\auth\SystemMenu;
use app\common\model\log\OperationLog;
use ReflectionClass;
use Exception;
use tmcore\base\BaseService;

/**
 * 操作日志服务类
 */
class OperationService extends BaseService
{

    /**
     * 获取可用参数
     * @param $params
     * @return mixed
     */
    private function getUsableParam($params) {
        // 屏蔽敏感信息
        if (isset($params['password'])) {
            $params['password'] = '******';
        }
        if (isset($params['password_confirm'])) {
            $params['password_confirm'] = '******';
        }
        return  $params;
    }

    /**
     * 获取方法注释
     * @param $request
     * @return mixed|string
     */
    private function getMethodAnnotation($request) {

        try {
            $controller = str_replace('.', '\\', $request->controller());
            $controller = '\\app\\' . app('http')->getName() . '\\controller\\' . $controller;
            $controllerClass = invoke($controller);
            if(!$controllerClass) throw new Exception('找不到控制器');

            $re = new ReflectionClass($controllerClass);
            $doc = $re->getMethod($request->action())->getDocComment();
            if (empty($doc)) {
                throw new Exception('没有给控制器方法添加注释 ' . $doc);
            }
            preg_match('/\s(\w+)/u', $re->getMethod($request->action())->getDocComment(), $values);
            return $values[0];
        } catch (Exception $e) {
            return $e->getMessage();
        }
    }

    /**
     * 获取请求方式
     * @param $request
     * @return string
     */
    private function getRequestType($request) {
        if($request->isGet()) {
            return 'GET';
        } elseif ($request->isPost()) {
            return 'POST';
        } elseif ($request->isDelete()) {
            return 'DELETE';
        } elseif ($request->isPut()) {
            return 'PUT';
        } else {
            return '';
        }
    }

    /**
     * 循环获取菜单名称
     * @param string $rule
     * @param int $pid
     * @param string $menu_name
     * @return string
     */
    public function getMenuName($rule = '', $pid = 0, $menu_name = '')
    {
        if($rule) {
            $row = SystemMenu::where(['perms' => $rule])->field('id,pid,name')->findOrEmpty();
            if(empty($row['name'])) return '';
            if(isset($row['pid']) && $row['pid']) return $this->getMenuName('', $row['pid'], $row['name']);
        }

        if($pid) {
            $row = SystemMenu::where(['id' => $pid])->field('id,pid,name')->findOrEmpty();
            if(isset($row['name']) && $row['name']) $menu_name =  $row['name'] . ' / ' . $menu_name;
            if(isset($row['pid']) && $row['pid']) return $this->getMenuName('', $row['pid'], $menu_name);
        }

        return trim($menu_name, '/');
    }

    /**
     * 添加操作记录
     * @param $request
     * @param $adminInfo
     * @param $response
     * @param $startTime
     * @param $endTime
     * @return bool
     */
    public function addOperation($request, $adminInfo, $response, $startTime = 0, $endTime = 0) {

        $rule = trim(strtolower($request->rule()->getRule())); //路由地址

        $executeTime = 0; // 执行时间
        if(!$endTime) $endTime = microtime(true);
        if($startTime && $endTime) {
            $executeTime  = number_format(($endTime - $startTime), 4);
        }

        if(is_array($response)) {
            $response_content = json_encode($response, 320);
            $result = $response;
        } else {
            $response_content = $response->getContent();
            $result = json_decode($response_content, true);
        }

        if(OperationLog::$error) {
            $status = 0;
        } else {
            if(isset($result['code']) && $result['code'] == 0) {
                $status = 1;
            } else {
                $status = 2;
            }
        }

        $data = [
            'admin_id' => $adminInfo['id'] ?? 0,
            'admin_name' => $adminInfo['name'] ?? '',
            'account' => $adminInfo['account'] ?? '',
            'action' => $this->getMethodAnnotation($request),
            'auth_menu' => $this->getMenuName($rule),
            'module' => app('http')->getName(),
            'url' => $request->url(),
            'type' => $this->getRequestType($request),
            'ua' => $request->header('User-Agent'),
            'params' => json_encode($this->getUsableParam($request->param()), 320),
            'ip' => $request->ip(),
            'result' => $status>0?$response_content:'',
            'error' => $status == 0?OperationLog::$error:'',
            'trace' => $status == 0?OperationLog::$trace:'',
            'execute_time' => $executeTime,
            'status' => $status
        ];

        return OperationLog::add($data);
    }


}